<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page isELIgnored="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Groupie - Chapter 8</title>
	<link rel="stylesheet" href="/strophe/public/css/jquery-ui-1.8.21.custom.css">
	<link rel="stylesheet" href="/strophe/public/css/groupie.css">
	<script type="text/javascript" src="/strophe/public/js/jquery-1.7.2.min.js"></script>
	<script type="text/javascript" src="/strophe/public/js/jquery-ui-1.8.21.custom.min.js"></script>
	<script type="text/javascript" src="/strophe/public/js/strophe.js"></script>
	<script type="text/javascript" src="/strophe/public/js/flXHR.js"></script>
	<script type="text/javascript" src="/strophe/public/js/strophe.flxhr.js"></script>
	<script type="text/javascript">
		var Groupie = {
			connection: null,
			room: null,
			nickname: null,
			NS_MUC: "http://jabber.org/protocol/muc",
			joined: null,
			participants: null,
			
			onPresence: function(presence) {
				var from = $(presence).attr('from');
				var room = Strophe.getBareJidFromJid(from);
				
				// make sure this presence is for the right room
				if (room != Groupie.room) return true;
				
				var nick = Strophe.getResourceFromJid(from);
				
				if ($(presence).attr('type') == 'error' && !Groupie.joined) {
					// error joining rooml; reset app
					Groupie.connection.disconnect();
				}
				else if (!Groupie.participants[nick] && $(presence).attr('type') != 'unavailable') {
					// add to participant list
					var jid = $(presence).find('item').attr('jid');
					Groupie.participants[nick] = jid || true;
					$('#participant-list').append("<li>" + nick + "</li>");
					
					if (Groupie.joined) {
						$(document).trigger("user_joined", nick);
					}
				}
				else if (Groupie.participants[nick] && $(presence).attr('type') == 'unavailable') {
					// remove from participants list
					$('#participant-list li').each(function() {
						if (nick == $(this).text()) {
							$(this).remove();
							Groupie.participants[nick] = false;
						}
					});
					
					$(document).trigger("user_left", nick);
				}
				
				if ($(presence).attr('type') != 'error' && !Groupie.joined) {
					// check for status 110 to see if it's our own presence
					if ($(presence).find("status[code='110']").length > 0 || nick == Groupie.nickname) {
						// check if server changed our nick
						if ($(presence).find("status[code='210']").length > 0) {
							Groupie.nickname = Strophe.getResourceFromJid(from);
						}
						
						// room join complete
						$(document).trigger("room_joined");
					}
				}
				
				return true;
			},
			
			onPublicMessage: function(message) {
				var from = $(message).attr('from');
				var room = Strophe.getBareJidFromJid(from);
				var nick = Strophe.getResourceFromJid(from);
				
				// make sure message is from the right place
				if (room == Groupie.room) {
					// is message from a user or the room itself?
					var notice = !nick;
					
					// message from ourselves will be styled differently
					var nickClass = "nick";
					if (nick == Groupie.nickname) {
						nickClass += " self";
					}
					
					var body = $(message).children('body').text();
					var delayed = $(message).children("delay").length > 0 
							|| $(message).children("x[xmlns='jabber:x:delay']").length > 0;
					
					// look for room topic change
					var subject = $(message).children('subject').text();
					if (subject) {
						if ($('#room-topic').text() == "") {
							body = "Subject is " + subject;
						}
						else {
							body = "Subject changed to " + subject;
							if (nick) body += " by " + nick;
						}
						
						$('#room-topic').text(subject);
						notice = true;
					}
							
					// normal chat message
					if (!notice) {
						var delayClass = delayed ? " delayed" : "";
					
						var action = body.match(/\/me (.*)$/);
						if (action) {
							// action message
							Groupie.addMessage(
								  "<div class='message action" + delayClass + "'>* " + nick + " " + action[1] + "</div>"	
							);								
						}
						else {
							// normal message
							Groupie.addMessage(
								  "<div class='message" + delayClass + "'>"
								+ "&lt;<span class='" + nickClass + "'>" + nick + "</span>&gt;"
								+ "<span class='body'>" + body + "</span>"
								+ "</div>"
							);
						}
						
					}
					else {
						Groupie.addMessage(
							  "<div class='notice'>*** " + body + "</div>"
						);
					}
					
				}
				
				return true;
			},
			
			onPrivateMessage: function(message) {
				var from = $(message).attr('from');
				var room = Strophe.getBareJidFromJid(from);
				var nick = Strophe.getResourceFromJid(from);
				
				// make sure message is from the right place
				if (room == Groupie.room) {
					var body = $(message).children('body').text();
					Groupie.addMessage(
						  "<div class='message private'>"
						+ "@@ &lt;<span class='nick'>" + nick + "</span>&gt;"
						+ "<span class='body'>" + body + "</span> @@"
						+ "</div>"
					);
				}
				
				return true;
			},
			
			addMessage: function(message) {
				// detect if we are scrolled all the way down
				var row = $('#chat').get(0);
				var atBottom = row.scrollTop >= row.scrollHeight - row.clientHeight;
				
				$('#chat').append(message);
				
				// if we were at the bottom, keep us at the bottom
				if (atBottom) {
					row.scrollTop = row.scrollHeight;
				}
			},
			
			showStatus: function(status) {
				$('#status').text(status);
			},
			
			log: function(message) {
				$('#log').prepend("<div>" + message + "</div>")
			}
		};
		
		$(document).ready(function() {
			$('#login_dialog').dialog({
				autoOpen: true,
				draggable: false,
				modal: true,
				title: "Join a Room",
				buttons: {
					"Join": function() {
						Groupie.room = $('#room').val();
						Groupie.nickname = $('#nickname').val();
						
						$(document).trigger('connect', {
							jid: $('#jid').val(),
							password: $('#password').val()
						});
						
// 						$('#password').val('');
						$(this).dialog('close');
					}
				}
			});
			
			// leave room
			$('#leave').click(function() {
				Groupie.connection.send(
					$pres({to: Groupie.room + "/" + Groupie.nickname, type: "unavailable"})
				);
				Groupie.connection.disconnect();
			});
			
			// send messages
			$('#input').keypress(function(ev) {
				if (ev.which == 13) {
					ev.preventDefault();
					
					var body = $(this).val();
					
					var match = body.match(/^\/(.*?)(?: (.*))?$/);
					var args = null;
					if (match) {
						if (match[1] == "msg") {
							// send private message
							args = match[2].match(/^(.*?) (.*)$/);
							if (Groupie.participants[args[1]]) {
								Groupie.connection.send(
									$msg({to: Groupie.room + "/" + args[1], type: "chat"}).c('body').t(args[2])	
								);
								Groupie.addMessage(
									  "<div class='message private'>"
									+ "@@ &lt;<span class='nick self'>" + Groupie.nickname + "</span>&gt;"
									+ "<span class='body'>" + args[2] + "</span> @@"
								);
							}
							else {
								Groupie.addMessage("<div class='notice error'>Error: User not in room.</div>");
							}
						}
						else if (match[1] == "me" || match[1] == "action") {
							// send action message
							Groupie.connection.send(
								$msg({to: Groupie.room, type: "groupchat"}).c('body').t('/me ' + match[2])
							);
						}
						else if (match[1] == "topic") {
							// change room topic
							Groupie.connection.send(
								$msg({to: Groupie.room, type: "groupchat"}).c('subject').t(match[2])
							);
						}
						else if (match[1] == "kick") {
							// kick out a troublemaker
							Groupie.connection.send(
								$iq({to: Groupie.room, type: "set"})
									.c('query', {xmlns: Groupie.NS_MUC + "#admin"})
									.c('item', {nick: match[2], role: "none"})
							);
						}
						else if (match[1] == "ban") {
							// ban a user
							Groupie.connection.send(
								$iq({to: Groupie.room, type: "set"})
									.c('query', {xmlns: Groupie.NS_MUC + "#admin"})
									.c('item', {jid: Groupie.participants[match[2]], affiliation: "outcast"})
							);
						}
						else if (match[1] == "op") {
							// add an administrator
							Groupie.connection.send(
								$iq({to: Groupie.room, type: "set"})
									.c('query', {xmlns: Groupie.NS_MUC + "#admin"})
									.c('item', {jid: Groupie.participants[match[2]], affiliation: "admin"})
							);
						}
						else if (match[1] == "deop") {
							// remove an adminsitrator
							Groupie.connection.send(
								$iq({to: Groupie.room, type: "set"})
									.c('query', {xmlns: Groupie.NS_MUC + "#admin"})
									.c('item', {jid: Groupie.participants[match[2]], affiliation: "none"})
							);
						}
						else {
							// send normal group chat message
							Groupie.addMessage("<div class='notice error'>Error: Command not recognized.</div>");
						}
					}
					else {
						Groupie.connection.send($msg({to: Groupie.room, type: "groupchat"}).c('body').t(body));
					}					
					
					$(this).val('');
				}
			});
		});
		
		$(document).bind('connect', function(ev, data) {
			var boshUrl = "${config.boshUrl}";
			Groupie.showStatus("Connecting to " + boshUrl);
			
			Groupie.connection = new Strophe.Connection(boshUrl);
			Groupie.connection.connect(data.jid, data.password, function(status) {
				if (status == Strophe.Status.CONNECTED) {
					$(document).trigger('connected');
				}
				else if (status == Strophe.Status.DISCONNECTED) {
					$(document).trigger('disconnected');
				}
			});
		});
		
		$(document).bind('connected', function() {
			Groupie.showStatus("Connected to XMPP server");
			
			Groupie.joined = false;
			Groupie.participants = {};

			// register handlers
			Groupie.connection.addHandler(Groupie.onPresence, null, "presence");
			Groupie.connection.addHandler(Groupie.onPublicMessage, null, "message", "groupchat");
			Groupie.connection.addHandler(Groupie.onPrivateMessage, null, "message", "chat");
			
			Groupie.connection.send($pres().c("priority").t("-1"));
			Groupie.connection.send(
				$pres({to: Groupie.room + "/" + Groupie.nickname}).c('x', {xmlns: Groupie.NS_MUC})
			);
		});
		
		$(document).bind('disconnected', function() {
			Groupie.showStatus("Disconnected from XMPP server");
			Groupie.connection = null;
			$('#participant-list').empty();
			$('#room-name').empty();
			$('#room-topic').empty();
			$('#chat').empty();
			$('#login_dialog').dialog('open');
		});
		
		$(document).bind('room_joined', function() {
			Groupie.showStatus("Joined room: " + Groupie.room);			
			Groupie.joined = true;
			
			$('#leave').removeAttr('disabled');
			$('#room-name').text(Groupie.room);
			
			$('#chat').append("<div class='notice'>*** Room joined.</div>");
		});
		
		$(document).bind('user_joined', function(ev, nick) {
			Groupie.addMessage("<div class='notice'>*** " + nick + " joined.</div>");
		});
		
		$(document).bind('user_left', function(ev, nick) {
			Groupie.addMessage("<div class='notice'>*** " + nick + " left.</div>");
		});
	</script>
</head>
<body>
	<h1>Groupie</h1>
	
	<div>
		<div id="status"></div>
		<div id="toolbar">
			<input type="button" id="leave" value="Leave Room" disabled="disabled"> 
		</div>
	</div>
	
	<div id="chat-area">
		<div>
			<span id="room-name"></span>
			<span id="room-topic"></span>
		</div>
		<div id="chat"></div>
		<textarea id="input"></textarea>
	</div>
	
	<div id="participants">
		<ul id="participant-list"></ul>
	</div>
	
	<div id="log"></div>
	
	<!-- login dialog -->
	<div id="login_dialog" class="hidden">
		<label>JID:</label><input type="text" id="jid" value="sejoonlim@${config.xmppDomain}"><br>
		<label>Password:</label><input type="password" id="password" value="welcome1"><br>
		<label>Chat Room:</label><input type="text" id="room" value="public@conference.${config.xmppDomain}"><br>
		<label>Nickname:</label><input type="text" id="nickname" value="sejoonlim">
	</div>
</body>
</html>